#include <filesystem>
#include <string>

#include "ServerConfigure.h"
#include "Log.h"
#include "GameThreadPool.hpp"
#include "GameSingleton.h"

#include "spdlog/spdlog.h"
#include "nlohmann/json.hpp"
#include "Utils/Utils.h"
#include "Engine/GameGuid.h"


#include "Managers/GameManager.h"
#include "Managers/SkinsManager.h"
#include "Managers/BlocksManager.h"
#include "Managers/ComponentsManager.h"
#include "Managers/FurnaceRecipesManager.h"
#include "Managers/CraftingRecipesManager.h"
#include "Managers/PlantsManager.h"
#include "Managers/ChangeManager.h"
#include "Managers/EntityManager.h"

#include "Subsystems/SubsystemTimeOfDay.h"
#include "Subsystems/SubsystemGameInfo.h"
#include "Subsystems/SubsystemTerrain.h"
#include "Subsystems/SubsystemExplosions.h"
#include "Subsystems/SubsystemInventories.h"
#include "Subsystems/SubsystemPlayers.h"
#include "Subsystems/SubsystemPickables.h"
#include "Subsystems/SubsystemProjectiles.h"
#include "Subsystems/SubsystemBodies.h"
#include "Subsystems/SubsystemMovingBlocks.h"
#include "Subsystems/SubsystemWeather.h"
#include "Subsystems/SubsystemBlockEntities.h"
#include "Subsystems/SubsystemAnimalEntities.h"



#include "Subsystems/BlockBehaviors/SubsystemBlockBehaviors.h"
#include "Subsystems/BlockBehaviors/SubsystemWaterBlockBehavior.h"
#include "Subsystems/BlockBehaviors/SubsystemMagmaBlockBehavior.h"

#include "Subsystems/BlockBehaviors/SubsystemFireBlockBehavior.h"
#include "Subsystems/BlockBehaviors/SubsystemMetersBlockBehavior.h"
#include "Subsystems/BlockBehaviors/SubsystemSnowBlockBehavior.h"
#include "Subsystems/BlockBehaviors/SubsystemSignBlockBehavior.h"
#include "Subsystems/BlockBehaviors/SubsystemChestBlockBehavior.h"
#include "Subsystems/BlockBehaviors/SubsystemFurnaceBlockBehavior.h"
#include "Subsystems/BlockBehaviors/SubsystemCraftingTableBlockBehavior.h"
#include "Subsystems/BlockBehaviors/SubsystemThrowableBlockBehavior.h"
#include "Subsystems/BlockBehaviors/SubsystemTorchBlockBehavior.h"
#include "Subsystems/BlockBehaviors/SubsystemMusketBlockBehavior.h"
#include "Subsystems/BlockBehaviors/SubsystemMatchBlockBehavior.h"
#include "Subsystems/BlockBehaviors/SubsystemCrossbowBlockBehavior.h"
#include "Subsystems/BlockBehaviors/SubsystemBowBlockBehavior.h"
#include "Subsystems/BlockBehaviors/SubsystemArrowBlockBehavior.h"
#include "Subsystems/BlockBehaviors/SubsystemRotBlockBehavior.h"

#include "Subsystems/BlockBehaviors/SubsystemWoodBlockBehavior.h"
#include "Subsystems/BlockBehaviors/SubsystemFenceBlockBehavior.h"
#include "Subsystems/BlockBehaviors/SubsystemFenceGateBlockBehavior.h"
#include "Subsystems/BlockBehaviors/SubsystemIvyBlockBehavior.h"
#include "Subsystems/BlockBehaviors/SubsystemFireworksBlockBehavior.h"
#include "Subsystems/BlockBehaviors/SubsystemCarpetBlockBehavior.h"
#include "Subsystems/BlockBehaviors/SubsystemCampfireBlockBehavior.h"
#include "Subsystems/BlockBehaviors/SubsystemBulletBlockBehavior.h"
#include "Subsystems/BlockBehaviors/SubsystemBucketBlockBehavior.h"
#include "Subsystems/BlockBehaviors/SubsystemWaterPlantBlockBehavior.h"
#include "Subsystems/BlockBehaviors/SubsystemBottomSuckerBlockBehavior.h"
#include "Subsystems/BlockBehaviors/SubsystemFertilizerBlockBehavior.h"

#include "Subsystems/BlockBehaviors/SubsystemCactusBlockBehavior.h"
#include "Subsystems/BlockBehaviors/SubsystemCollapsingBlockBehavior.h"

#include "Subsystems/BlockBehaviors/SubsystemDoorBlockBehavior.h"
#include "Subsystems/BlockBehaviors/SubsystemGrassBlockBehavior.h"
#include "Subsystems/BlockBehaviors/SubsystemGrassTrapBlockBehavior.h"
#include "Subsystems/BlockBehaviors/SubsystemGravestoneBlockBehavior.h"
#include "Subsystems/BlockBehaviors/SubsystemPlantBlockBehavior.h"
#include "Subsystems/BlockBehaviors/SubsystemRakeBlockBehavior.h"
#include "Subsystems/BlockBehaviors/SubsystemSaplingBlockBehavior.h"
#include "Subsystems/BlockBehaviors/SubsystemSoilBlockBehavior.h"
#include "Subsystems/BlockBehaviors/SubsystemTrapdoorBlockBehavior.h"
#include "Subsystems/BlockBehaviors/SubsystemTreasureGeneratorBlockBehavior.h"


using namespace PocketSurvival::Engine;

namespace PocketSurvival
{
    static int32_t tickWaitTime = 100;

    GameManager::GameManager()
    {
        GameSingleton::blocksManager = GameSingleton::singletonPtr->registerSingleton<BlocksManager>();
        GameSingleton::changeManager = GameSingleton::singletonPtr->registerSingleton<ChangeManager>();
        GameSingleton::componentsManager = GameSingleton::singletonPtr->registerSingleton<ComponentsManager>();
        GameSingleton::craftingRecipesManager = GameSingleton::singletonPtr->registerSingleton<CraftingRecipesManager>();
        GameSingleton::entityManager = GameSingleton::singletonPtr->registerSingleton<EntityManager>();
        GameSingleton::furnaceRecipesManager = GameSingleton::singletonPtr->registerSingleton<FurnaceRecipesManager>();
        GameSingleton::plantsManager = GameSingleton::singletonPtr->registerSingleton<PlantsManager>();
        GameSingleton::skinsManager = GameSingleton::singletonPtr->registerSingleton<SkinsManager>();

        
        registerSubsystem<SubsystemTimeOfDay>();
        registerSubsystem<SubsystemGameInfo>();
        registerSubsystem<SubsystemTerrain>();
        registerSubsystem<SubsystemExplosions>();
        registerSubsystem<SubsystemInventories>();
        registerSubsystem<SubsystemPlayers>();
        registerSubsystem<SubsystemPickables>();
        registerSubsystem<SubsystemProjectiles>();
        registerSubsystem<SubsystemBodies>();
        registerSubsystem<SubsystemMovingBlocks>();
        registerSubsystem<SubsystemWeather>();
        registerSubsystem<SubsystemBlockEntities>();
        registerSubsystem<SubsystemAnimalEntities>();

        registerSubsystem<SubsystemBlockBehaviors>();
        registerSubsystem<SubsystemWaterBlockBehavior>();
        registerSubsystem<SubsystemMagmaBlockBehavior>();

        registerSubsystem<SubsystemFireBlockBehavior>();
        registerSubsystem<SubsystemMetersBlockBehavior>();
        registerSubsystem<SubsystemSnowBlockBehavior>();
        registerSubsystem<SubsystemSignBlockBehavior>();
        registerSubsystem<SubsystemChestBlockBehavior>();
        registerSubsystem<SubsystemFurnaceBlockBehavior>();
        registerSubsystem<SubsystemCraftingTableBlockBehavior>();
        registerSubsystem<SubsystemThrowableBlockBehavior>();
        registerSubsystem<SubsystemTorchBlockBehavior>();
        registerSubsystem<SubsystemMusketBlockBehavior>();
        registerSubsystem<SubsystemMatchBlockBehavior>();
        registerSubsystem<SubsystemCrossbowBlockBehavior>();
        registerSubsystem<SubsystemBowBlockBehavior>();
        registerSubsystem<SubsystemArrowBlockBehavior>();
        registerSubsystem<SubsystemRotBlockBehavior>();

        registerSubsystem<SubsystemWoodBlockBehavior>();
        registerSubsystem<SubsystemFenceBlockBehavior>();
        registerSubsystem<SubsystemFenceGateBlockBehavior>();
        registerSubsystem<SubsystemIvyBlockBehavior>();
        registerSubsystem<SubsystemFireworksBlockBehavior>();
        registerSubsystem<SubsystemCarpetBlockBehavior>();
        registerSubsystem<SubsystemCampfireBlockBehavior>();
        registerSubsystem<SubsystemBulletBlockBehavior>();
        registerSubsystem<SubsystemBucketBlockBehavior>();
        registerSubsystem<SubsystemWaterPlantBlockBehavior>();
        registerSubsystem<SubsystemBottomSuckerBlockBehavior>();
        registerSubsystem<SubsystemFertilizerBlockBehavior>();

        registerSubsystem<SubsystemCactusBlockBehavior>();
        registerSubsystem<SubsystemCollapsingBlockBehavior>();

        registerSubsystem<SubsystemDoorBlockBehavior>();
        registerSubsystem<SubsystemGrassBlockBehavior>();
        registerSubsystem<SubsystemGrassTrapBlockBehavior>();
        registerSubsystem<SubsystemGravestoneBlockBehavior>();
        registerSubsystem<SubsystemPlantBlockBehavior>();
        registerSubsystem<SubsystemRakeBlockBehavior>();
        registerSubsystem<SubsystemSaplingBlockBehavior>();
        registerSubsystem<SubsystemSoilBlockBehavior>();
        registerSubsystem<SubsystemTrapdoorBlockBehavior>();
        registerSubsystem<SubsystemTreasureGeneratorBlockBehavior>();


        tickWaitTime = 1000 / GameSingleton::serverConfigure->tick;
    }
    
    GameManager::~GameManager() {}

    void GameManager::update(float dt)
    {
        auto lastTime = std::chrono::steady_clock::now();
        for(Subsystem *subsystem : m_singleUpdateSubsystemSet)
        {
            subsystem->update(dt);
        }
        auto nowTime = std::chrono::steady_clock::now();
        auto msec = std::chrono::duration_cast<std::chrono::milliseconds>(nowTime - lastTime).count();
        // 占用太多时间的话，就打印出日志，以方便优化
        if (msec > tickWaitTime)
        {
            Log::Info(fmt::format("单线程的子系统运行总时间 : {}ms", msec));
        }

        for(Subsystem *subsystem : m_threadUpdateSubsystemSet)
        {
            GameSingleton::gameThreadPool->push_task([dt, subsystem]{
                auto lastTime = std::chrono::steady_clock::now();
                try
                {
                    subsystem->update(dt);
                }
                catch(const std::exception& e)
                {
                    Log::Error(fmt::format("[{}]子线程循环发生错误 : {}", subsystem->getName(), e.what()));
                }
                auto nowTime = std::chrono::steady_clock::now();
                auto msec = std::chrono::duration_cast<std::chrono::milliseconds>(nowTime - lastTime).count();
                
                // 如果某个子系统占用太多时间的话，就打印出日志，以方便优化
                if (msec > tickWaitTime)
                {
                    Log::Info(fmt::format("{} : {}ms", subsystem->getName(), msec));
                }
            });
        }

        GameSingleton::gameThreadPool->wait_for_tasks();

        GameSingleton::changeManager->update(dt);
        GameSingleton::componentsManager->update(dt);
    }


    void GameManager::loadGame()
    {
        GameSingleton::blocksManager->loadGame();
        GameSingleton::changeManager->loadGame();
        GameSingleton::componentsManager->loadGame();
        GameSingleton::craftingRecipesManager->loadGame();
        GameSingleton::entityManager->loadGame();
        GameSingleton::furnaceRecipesManager->loadGame();
        GameSingleton::plantsManager->loadGame();
        GameSingleton::skinsManager->loadGame();



        // 读取的存档目录
        m_nowWorldPath = fmt::format("./Worlds/{}",GameSingleton::serverConfigure->worldDefaultName);
        // 该存档的地形文件存档目录
        m_nowWorldMapsPath = m_nowWorldPath + "/Regions";
        // 该存档的玩家数据文件存档目录
        m_nowWorldPlayersPath = m_nowWorldPath + "/Players";

        if(std::filesystem::exists(m_nowWorldMapsPath) == false)
        {
            if(std::filesystem::create_directories(m_nowWorldMapsPath) == false)
            {
                throw std::runtime_error("检测不到地图文件夹，并且无法创建新的地图文件夹");
            }
        }
        if(std::filesystem::exists(m_nowWorldPlayersPath) == false)
        {
            if(std::filesystem::create_directories(m_nowWorldPlayersPath) == false)
            {
                throw std::runtime_error("检测不到玩家文件夹，并且无法创建新的玩家文件夹");
            }
        }

        std::string jsonText;
        nlohmann::json subsystemJson = {};
        if(Utils::LoadTextFile(m_nowWorldPath + "/Subsystems.json", jsonText))
        {
            subsystemJson = nlohmann::json::parse(jsonText);
        }

        // 加载子系统数据
        nlohmann::json nullJson = {};
        for(int32_t echelon = 0; echelon < 10; ++echelon)
        {
            for(auto &pair : subsystemMap)
            {
                if(pair.second->getLoadEchelon() == (SubLoadEchelon)echelon)
                {
                    if(subsystemJson.find(pair.second->getName()) != subsystemJson.end())
                    {
                        pair.second->load(subsystemJson[pair.second->getName()]);
                    }
                    else
                    {
                        pair.second->load(nullJson);
                    }
                }
            }
        }

        // 注册子系统更新方式

        for(auto &pair : subsystemMap)
        {
            if (pair.second->getUpdateType() == SubUpdateType::MainSingleUpdate)
            {
                m_singleUpdateSubsystemSet.insert(pair.second);
            }
            else if (pair.second->getUpdateType() == SubUpdateType::MultiThreadUpdate)
            {
                m_threadUpdateSubsystemSet.insert(pair.second);
            }
        }
    }


    void GameManager::saveGame()
    {
        nlohmann::json subsystemJson = {};
        for(auto &pair : subsystemMap)
        {
            nlohmann::json saveJson = {};
            pair.second->save(saveJson);
            if(saveJson.is_null() == false)
            {
                subsystemJson[pair.second->getName()] = saveJson;
            }
        }

        if(Utils::SaveTextFile(m_nowWorldPath + "/Subsystems.json", subsystemJson.dump()) == false)
        {
            Log::Error("Subsystem.json 文件保存失败");
        }
    }

    void GameManager::saveGameToMsgJson(nlohmann::json &jsonData)
    {
        MSG_VALUE_SET(jsonData, "Guid", "System.Guid", GameGuid::GetZeroGuid().toString());
        MSG_VALUE_SET(jsonData, "Name", "string", "GameProject");

        nlohmann::json subsystemsJson = nlohmann::json::object();

        for(auto &pair : subsystemMap)
        {
            nlohmann::json subJson;
            pair.second->saveToMsgJson(subJson);
            if(subJson.is_null() == false)
            {
                subsystemsJson[pair.second->getName()] = subJson;
            }
        }
        jsonData["Subsystems"].swap(subsystemsJson);
    }

} // namespace PocketSurvival
